package com.google.code.timeeditapplication.controller.implementation;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

import com.google.code.timeeditapplication.controller.IScheduleController;
import com.google.code.timeeditapplication.model.implementation.Schedule;
import com.google.code.timeeditapplication.model.implementation.ScheduleItem;

public class ScheduleController implements IScheduleController {

	private static IScheduleController iSC;
	// private GregorianCalendar calendar = new GregorianCalendar();
	private Schedule activeSchedule;
	private Schedule daySchedule;
	private Date startDate;
	private Date endDate;
	private Date activeDate;
	private final ArrayList<Schedule> weekScheduleList = new ArrayList<Schedule>();

	private ScheduleController() {

	}

	public static IScheduleController getInstance() {

		if (iSC == null) {
			iSC = new ScheduleController();
		}

		return iSC;

	}

	/*
	 * Creates a list containing seven schedules. Each schedule corresponds to a
	 * day in the week, where place 0 in the list equals monday and place 6
	 * equals sunday. The week is set after the active date and schedule is set
	 * after the active schedule
	 */

	private void setWeek() {
		setStartOfWeek();

		for (int i = 0; i < 7; i++) {

			this.endDate = rollDate(0, false, this.startDate);

			this.weekScheduleList.add(new Schedule(
					_insertScheduleItems(this.activeSchedule.getItems()),
					this.activeSchedule.getName(), this.activeSchedule
							.getMetaData()));
			this.startDate = rollDate(1, true, this.startDate);
		}

		// activeScheduleItems = _insertScheduleItems(schedule.getItems());

		/*
		 * returnSchedule = new Schedule(activeScheduleItems,
		 * schedule.getName(), schedule.getMetaData());
		 */

	}

	// Sets startDate to monday 00.00 and endDate to monday 23.59
	private void setStartOfWeek() {

		final int day = this.activeDate.getDay() + 1;

		switch (day) {
		case Calendar.MONDAY:
			this.startDate = rollDate(0, true, this.activeDate);
			break;
		case Calendar.TUESDAY:
			this.startDate = rollDate(-1, true, this.activeDate);
			break;
		case Calendar.WEDNESDAY:
			this.startDate = rollDate(-2, true, this.activeDate);
			break;
		case Calendar.THURSDAY:
			this.startDate = rollDate(-3, true, this.activeDate);
			break;
		case Calendar.FRIDAY:
			this.startDate = rollDate(-4, true, this.activeDate);
			break;
		case Calendar.SATURDAY:
			this.startDate = rollDate(-5, true, this.activeDate);
			break;
		case Calendar.SUNDAY:
			this.startDate = rollDate(-6, true, this.activeDate);
			break;
		}
		this.endDate = (Date) this.startDate.clone();
	}

	/*
	 * Takes all scheduleItems, which takes place after the startDate and before
	 * the endDate, and inserts them into activeList
	 */
	private ArrayList<ScheduleItem> _insertScheduleItems(
			final ArrayList<ScheduleItem> scheduleItems) {

		final ArrayList<ScheduleItem> activeItems = new ArrayList<ScheduleItem>();

		for (final ScheduleItem m : scheduleItems) {

			if (this.startDate.before(m.getStartTime().getTime())
					&& this.endDate.after(m.getEndTime().getTime())) {
				activeItems.add(m);
			}
		}
		return activeItems;
	}

	/*
	 * Rolldate sets the startDate and endDate depending on boolean variable
	 * "start". It rolls the Date date according to the value.
	 */
	private Date rollDate(final int value, final boolean start, final Date date) {
		final GregorianCalendar cloneCalendar = new GregorianCalendar();

		cloneCalendar.set(1900 + date.getYear(), date.getMonth(),
				date.getDate());
		cloneCalendar.add(Calendar.DATE, value);

		if (start) {
			cloneCalendar.set(Calendar.HOUR_OF_DAY,
					cloneCalendar.getActualMinimum(Calendar.HOUR_OF_DAY));
		} else {
			cloneCalendar.set(Calendar.HOUR_OF_DAY,
					cloneCalendar.getActualMaximum(Calendar.HOUR_OF_DAY));
		}

		final Date returnDate = cloneCalendar.getTime();

		return returnDate;

	}

	// Creates a schedule set to the active date and active schedule
	private void setDay() {

		final ArrayList<ScheduleItem> activeScheduleItems = _insertScheduleItems(this.activeSchedule
				.getItems());

		this.daySchedule = new Schedule(activeScheduleItems,
				this.activeSchedule.getName(),
				this.activeSchedule.getMetaData());

	}

	public Schedule getDaySchedule() {
		setDay();
		return this.daySchedule;
	}

	public ArrayList<Schedule> getWeekSchedule() {
		setWeek();
		return this.weekScheduleList;
	}

	public void setActiveDate(final Date date) {
		this.activeDate = date;

		if (this.activeDate != null){
			this.startDate = rollDate(0, true, this.activeDate);
			this.endDate = rollDate(0, false, this.activeDate);
		}
	}

	public Date getActiveDate() {

		return this.activeDate;
	}

	public void setActiveSchedule(final Schedule schedule) {
		this.activeSchedule = schedule;
	}
}
